home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / language / embedded / mcu11 / div48.arc / DIV48.A11
Text File  |  1988-03-23  |  14KB  |  417 lines

  1. *  Demonstration program for 24 bit multiplication with 48 bit result
  2. *  and 24 bit division of a 48 bit dividend.
  3. *
  4. *  The multiplication routine is typical for 6803 class machines.
  5. *
  6. *  The division routine is unusual in that it uses the divide instruction
  7. *  of the 68HC11 to find a trial divisor, proceeding by bytes until the
  8. *  division is complete.   A divide takes about 800us.    The code is
  9. *  lengthy -- size was traded for speed.
  10. *
  11. *  If you find an error or you improve these routines by making them
  12. *  faster and shorter or if you have an approach which is faster,
  13. *  please contact me.
  14. *
  15. *     John Moran                (203)-575-3016
  16. *     Bristol Babcock Inc.
  17. *     1100 Buckingham St.
  18. *     Watertown, Conn. 06795
  19. *
  20. *
  21. * -----------------------------------------------------------------
  22. * Definition of RAM use, assumes M68HC11EVB Evaluation Board
  23.     ORG $DD00      ; Start of RAM.
  24. CNTR     RMB 1  ; Counter for mul/div
  25. DIVPTR   RMB 2  ; Ptr to MS byte of divisor
  26. DIVCNT   RMB 1  ; Number of bytes in the divisor
  27. DVDCNT   RMB 1  ; Number of bytes in the dividend
  28. QPTR     RMB 2  ; Ptr to current byte of quotient
  29. QCNT     RMB 1  ; Number of bytes remaining to be found in quotient
  30. TRIALQ   RMB 1  ; Current quotient trial value
  31.  
  32.     ORG $DD50      ; Temp storage for multiply
  33. A24      RMB 3  ; Argument for multiple precision mul
  34. B24      RMB 3  ; Argument for multiple precision mul
  35. A48      RMB 6  ; Product from multiple precision mul
  36.  
  37.     ORG $DD60      ; Temp storage for  divide
  38. D24      RMB 3  ; Divisor
  39. Q24      RMB 3  ; Quotient - Must immediately precede dividend
  40. D48      RMB 6  ; Dividend
  41.  
  42.     ORG $DD70      ; Temp storage for  divide
  43. TEMP     RMB 2  ; Work space for divide
  44. *
  45. *
  46. * -----------------------------------------------------------------
  47.  
  48. * BUFFALO's terminal I/O Hooks
  49. OUT1BYT  EQU    $FFBB
  50. OUT1BSP  EQU    $FFBE
  51. OUTSTRG  EQU    $FFC7
  52. OUTCRLF  EQU    $FFC4
  53. * 
  54. * =================================================================
  55. * Code space  - at C000-DFFF for debug. 
  56.     ORG $C000
  57. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  58. * Test routine entries:
  59.  
  60.          BRA    DIVTST  ; Use output of last multiply as dividend
  61.          BRA    MUL24
  62.          BRA    DIV24J
  63.  
  64.  
  65. DIV24J:  JMP    DIV24   ; Extend branch range
  66.  
  67. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  68.  
  69. *   Calculate the 48 bit unsigned product of two 24 bit unsigned numbers.
  70. *   Place the multiplicand in A24, the multiplier in B24, then JSR MUL24.
  71. *   Result is returned in A48.  Put smaller value in B24 when given a 
  72. *   choice.
  73. *             Note: A48 must immediately follow B24 in memory !!!!
  74. *   B24 may overlap A48 to save space if desired - some changes req'd.
  75. *   The approach used is similar to multiplication with pencil and paper,
  76. *   where bytes are used as if they were digits. It may be extended to
  77. *   any reasonable number of bytes quite easily.
  78.  
  79. MUL24:   PSHB           ; Preserve regs
  80.          PSHA
  81.          PSHX
  82.          LDX    #B24    ; Address of args
  83.          CLR    3,X     ; Clear A48
  84.          CLR    4,X
  85.          CLR    5,X
  86.          CLR    6,X
  87.          CLR    7,X
  88.          CLR    8,X
  89.          LDAA   #3      ; # bytes in multiplier
  90.          STAA   CNTR
  91.          OPT c
  92. MULOOP:  LDAA   2,X
  93.          BEQ    MULUP2  ; Skip if 0 multiplier
  94.          LDAB   A24+2   ; Least signifigant byte of multiplicand
  95.          MUL
  96.          ADDD   7,X
  97.          STD    7,X
  98.          BCC    MUL1
  99.          INC    6,X     ; Propagate the carry
  100.          BNE    MUL1
  101.          INC    5,X
  102. MUL1:    LDAA   2,X
  103.          LDAB   A24+1
  104.          MUL
  105.          ADDD   6,X
  106.          STD    6,X
  107.          BCC    MUL2
  108.          INC    5,X     ; Propagate Carry
  109. MUL2:    LDAA   2,X
  110.          LDAB   A24     ; Most signifigant byte
  111.          MUL
  112.          ADDD   5,X
  113.          STD    5,X     ; No carry possible on hi end
  114. MULUP2:  DEX            ; Move left 1 byte in multiplier & result
  115.          DEC    CNTR
  116.          BNE    MULOOP
  117.          PULX           ; Restore regs
  118.          PULA
  119.          PULB
  120.          RTS
  121.  
  122.          OPT noc
  123. *
  124. * 
  125. *        This is a test routine for MUL24 and DIV24.
  126. *        It calculates the product of two 24 bit numbers and then
  127. *        divides this product by each of the original factors, checking
  128. *        to ensure that the result is the other factor. It halts if an
  129. *        error is found. You can insert breakpoints if an error is found
  130. *        and then start again at C000 (Don't reload!!!) and it will 
  131. *        repeat the offending calculation. 
  132. *
  133. *        Takes about 2ms for the multiply and 2 divides.
  134. *
  135. *        After each successful test, the factors are adjusted by adding
  136. *        a prime number to select the next numbers to test.
  137. *        
  138. *        I let this test run for 9 days to check these routines.
  139. *
  140. DIVTST:  JSR    MUL24   ; CALCULATE PRODUCT
  141.          LDD    A24
  142.          STD    D24
  143.          LDAB   A24+2
  144.          STAB   D24+2
  145.          JSR    DIVPROD
  146.          LDAB   B24
  147.          CMPB   Q24
  148.          BNE    FAIL    ; QUIT IF ERROR
  149.          LDAB   B24+1
  150.          CMPB   Q24+1
  151.          BNE    FAIL
  152.          LDAB   B24+2
  153.          CMPB   Q24+2
  154.          BNE    FAIL
  155.          LDD    B24     ; CHECK THE MULTIPLIER TOO
  156.          STD    D24
  157.          LDAB   B24+2
  158.          STAB   D24+2
  159.          JSR    DIVPROD
  160.          LDAB   A24
  161.          CMPB   Q24
  162.          BNE    FAIL    ; QUIT IF ERROR
  163.          LDAB   A24+1
  164.          CMPB   Q24+1
  165.          BNE    FAIL
  166.          LDAB   A24+2
  167.          CMPB   Q24+2
  168.          BNE    FAIL
  169. * Looks OK, calculate next numbers to use as factors
  170. BUMPA:   LDD    #593    ; Prime number
  171.          ADDD   A24+1
  172.          STD    A24+1
  173.          BCC    BUMPB
  174.          INC    A24     ; Propagate carry
  175.          BEQ    BUMPA   ; Avoid 0
  176. BUMPB:   LDX    #B24 
  177.          INC    2,X     ; 1 is prime
  178.          BNE    BMPDUN
  179.          JSR    PRINT   ; Show that we're still OK
  180.          INC    1,X
  181.          BNE    BMPDUN
  182.          INC    0,X
  183.          BEQ    BUMPB   ; Avoid 0
  184. BMPDUN:  JMP    DIVTST  ;             LOOP FOREVER
  185.  
  186. *        Quotient didn't match one of the factors
  187. FAIL:    BSR    PRINT
  188.          LDX    #FAILSTR
  189.          JSR    OUTSTRG ; Announce the failure
  190. DIE:     NOP            ; Simulate a halt
  191.          JMP    DIE
  192.  
  193. PRINT:   PSHX
  194.          LDX    #A24    ; PRINT THE LAST ITEMS MULTIPLIED
  195.          JSR    OUT1BYT
  196.          JSR    OUT1BYT
  197.          JSR    OUT1BSP
  198.          JSR    OUT1BYT
  199.          JSR    OUT1BYT
  200.          JSR    OUT1BSP
  201.          JSR    OUTCRLF
  202.          PULX
  203.          RTS
  204.  
  205. FAILSTR  FCC    ' FAIL'
  206.          FCB    04
  207.  
  208. *
  209.  
  210.  
  211. DIVPROD: LDX    #A48    ; Copy product to dividend
  212.          LDAA   #6      ; 6 bytes = 48 bits
  213. DIVTLP:  LDAB   0,X
  214.          STAB   $10,X
  215.          INX
  216.          DECA
  217.          BNE    DIVTLP
  218. *                        ; Drop into divide subroutine
  219. * 
  220. *
  221. * Calculate the 24 bit unsigned quotient resulting from division of a
  222. * 48 bit dividend by a 24 bit divisor. Place the divisor in D24 and the
  223. * dividend in D48. The result will be returned in Q24.
  224.  
  225. *   The approach is similar to long division by hand, but here the
  226. * IDIV instruction is used to form the trial quotient. Care is taken
  227. * to ensure that the trial quotient is always <= the required quotient.
  228.  
  229. * The division routine can be modified to handle any reasonable number
  230. * of bytes, but it is more challenging than extending the multiplication
  231. * routine.
  232.  
  233. *   Typical operation is two passes through the loop per byte in the
  234. * dividend.
  235.  
  236.  
  237. DIV24:   PSHB
  238.          PSHA
  239.          PSHX
  240.          CLR    Q24     ; Clear quotient to 0
  241.          CLR    Q24+1
  242.          CLR    Q24+2
  243.          LDAB   #6      ; Size of dividend, max
  244.          LDY    #D48    ; Count bytes in the dividend
  245. DIV0:    TST    0,Y
  246.          BNE    DIV1
  247.          DECB
  248.          BEQ    DIVER1  ; Done if dividend = 0, Return 0
  249.          INY
  250.          BRA    DIV0
  251.  
  252. DIVER1:  JMP    DIVBY0  ; Extend branch range
  253.  
  254. *  Find size of divisor and dividend & thus the hi byte of quotient.
  255. *  Also do gross checks to avoid dividing by 0, etc.
  256. DIV1:    STAB   DVDCNT  ; Save # bytes in dividend
  257.          LDAA   #$FF
  258.          NEGB
  259.          ADDD   #D48+5  ; + Addr of LS Byte-1 in dividend
  260.          XGDY           ; Y points to MSB of dividend
  261.          LDA    #3      ; Count bytes in the divisor
  262.          LDX    #D24
  263. DIV1CT:  TST    0,X
  264.          BNE    DIV2
  265.          DECA
  266.          BEQ    DIVER1  ; Quit if divide by 0, Return 0
  267.          INX
  268.          BRA    DIV1CT
  269.  
  270. DIV2:    STX    DIVPTR  ; Ptr to MSB of divisor
  271.          STA    DIVCNT  ; Number of bytes in divisor
  272.          SUBA   DVDCNT
  273.          BGT    DIVER1  ; Quit if divisor > dividend, Return 0
  274.          LDAB   1,Y     ; Get hi byte of dividend
  275.          CMPB   0,X     ; IF hi byte of dividend > hi byte of divisor
  276.          BLO    DIV3    ;  THEN one more byte needed in the quotient
  277.          DECA
  278.          DEY            ;  and in Dividend
  279. DIV3:    TAB
  280.          NEGA           ; Make it positive
  281.          STAA   QCNT    ; # Bytes in quotient
  282.          CMPA   #4      ; ??? MAKE THIS PREVENT OVERFLOW ???
  283.          BGT    DIVER1  ; Quit if quotient too big, return 0
  284.          LDAA   #$FF    ; Make it a negative 16 bit value
  285.          ADDD   #Q24+2  ; Ptr to hi byte of quotient
  286.          STD    QPTR
  287.  
  288. *  Decide whether to use 1 or 2 bytes as trial divisor
  289. DIVLUP:  LDX    DIVPTR  ; Get ptr to MSB of divisor
  290.          LDAA   DIVCNT  ; Get # bytes in divisor
  291.          DECA
  292.          BEQ    DIV1BY  ; Only 1 byte in divisor
  293.          STA    CNTR    ; Temp, # bytes in divisor -1
  294.          LDD    1,Y     ; Get hi word of dividend in B
  295.          CPD    0,X     ; IF hi word of dividend < hi word of divisor
  296.          BLO    DIVBYB  ;  THEN use only MSB of divisor
  297.          BHI    DIVW2B  ; Divisor < Dividend  & 2+ bytes in divisor
  298.          LDA    CNTR
  299.          DECA
  300.          BEQ    DIVWRD  ; BR if divisor = MSB's of dividend
  301.          LDAB   3,Y     ; Get next byte of dividend in B
  302.          CMPB   2,X     ; IF next byte of dividend < this byte of divisor
  303.          BLO    DIVBYB  ;  THEN use only MSB of divisor, rounded up
  304.          LDAB   #1      ;  ELSE Trial Quotient = 1
  305.          BRA    DIVSTO
  306.  
  307. DIVBYB:  JMP    DIVBYT  ; Extend branch range
  308. DIV1BY:  JMP    DIV1BYT
  309.  
  310. *  Trial divisor is 2 bytes. Round up if required.
  311. DIVW2B:  LDA    CNTR
  312.          DECA           ; Make A = 0 if exactly 2 bytes in divisor
  313. DIVWRD:  LDX    0,X     ; Get MSW of divisor
  314.          TSTA
  315.          BEQ    DIVWNR  ; BR if exactly 2 bytes in divisor
  316.          INX            ; Round divisor up
  317. DIVWNR:  LDD    1,Y     ; Get MSW of dividend
  318.          IDIV
  319.          XGDX           ; Get trial quotient into B
  320. *  Multiply divisor by trial quotient and subtract from dividend
  321. DIVSTO:  STAB   TRIALQ  ; Save trial quotient
  322.          LDX    QPTR
  323.          ADDB   0,X     ; Add Trial Q to current Q
  324.          STAB   0,X
  325.          LDAB   DIVCNT
  326.          STAB   CNTR
  327.          LDX    DIVPTR
  328.          LDAA   0,X     ; Get hi byte of divisor
  329.          LDAB   TRIALQ  ; Get trial quotient byte
  330.          MUL
  331.          STD    TEMP    ; Seems crude, but it works...
  332.          LDD    0,Y
  333.          SUBD   TEMP    ; No borrow possible from hi byte
  334.          STD    0,Y
  335.          DEC    CNTR
  336.          BEQ    DIVLND ; BR if divisor is 1 byte
  337.          LDX    DIVPTR
  338.          LDAA   1,X    ; Get next byte of divisor
  339.          LDAB   TRIALQ
  340.          MUL
  341.          STD    TEMP
  342.          LDD    1,Y
  343.          SUBD   TEMP
  344.          STD    1,Y 
  345.          BCC    *+5
  346.          DEC    0,Y     ; Propagate borrow
  347.          DEC    CNTR
  348.          BEQ    DIVLND  ; BR if divisor is 2 bytes
  349.          LDX    DIVPTR
  350.          LDAA   2,X
  351.          LDAB   TRIALQ
  352.          MUL
  353.          STD    TEMP
  354.          LDD    2,Y
  355.          SUBD   TEMP
  356.          STD    2,Y
  357.          BCC    DIVLND
  358.          LDX    0,Y     ; Propagate borrow
  359.          DEX
  360.          STX    0,Y
  361. DIVLND:  LDD    0,Y
  362.          BEQ    DIVDN0
  363.          TSTA
  364.          BEQ    DIVLN2  ; Almost always branches, 4000:1 or so
  365.          LDX    DIVPTR  ; Ptr to MSB of divisor
  366.          BRA    DIVBYR  ; Last divide by byte was too coarse, correct it
  367.  
  368. DIVDN0:  INY            ; Hi word of dividend=0, move 1 position right
  369.          DEC    QCNT
  370.          BLT    DIVDUN
  371.          INC    QPTR+1
  372. DIVLN2:  JMP    DIVLUP  ; Loop to do next byte
  373.  
  374. *  Trial divisor is hi byte of divisor.  Always round it up.
  375. DIVBYT:  DEC    QCNT    ; Divisor > dividend, move 1 position right
  376.          BLT    DIVDUN  ; BR if done
  377.          INC    QPTR+1
  378.          INY
  379. DIVBYR:  LDAB   0,X     ; Get MSB of divisor
  380.          CLRA
  381.          XGDX
  382.          INX            ; Round divisor up
  383.          LDD    0,Y     ; Dividend, current hi 16 bits
  384.          BEQ    DIVDN0  ; Shortcut on 0 dividend     ?? Does this help??
  385.          IDIV           ; MSW of dividend / MSB of divisor = Trial Q
  386.          XGDX           ; Get quotient in D
  387.          TSTA
  388.          BEQ    DIVBT2
  389.          LDAB   #$F0    ; Overflow on this trial, force max 
  390. DIVBT2:  JMP    DIVSTO
  391.  
  392. * Handle single byte divisor specially
  393. DIV1BYT: LDAB   0,X     ; Get divisor, single byte
  394.          CLRA   
  395.          XGDX
  396. DIV1SKP: CPX    0,Y
  397.          BLS    DIV1BGO 
  398.          DEC    QCNT   ; Divisor > Dividend,  move 1 position right
  399.          BLT    DIVDUN  ; BR if done
  400.          INC    QPTR+1
  401.          INY
  402.          BRA    DIV1SKP
  403. DIV1BGO: LDD    0,Y     ; Dividend, current hi 16 bits
  404.          IDIV           ; MSW of dividend / divisor = Trial Q
  405.          XGDX           ; Get quotient in D
  406.          JMP    DIVSTO
  407.  
  408. DIVDUN:
  409. DIVBY0:  PULX           ; Restore regs
  410.          PULA
  411.          PULB
  412.          RTS
  413.  
  414.       END
  415.  
  416.  
  417.